package com.example.demo.util;

import com.example.demo.annotation.ExcelProperty;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 *	Excel 导出工具类
 *
 */
public class ExcelWriterUtils {

    /**
     * 导出 excel
     * @param dataList 数据集合
     * @param fileName 文件名
     * @param response response
     */
    public static void writer(List<?> dataList, String fileName, HttpServletResponse response) throws Exception {
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
        OutputStream outputStream = response.getOutputStream();
        writer(dataList, fileName, outputStream);
    }


    /**
     * 导出 excel
     * @param dataList 数据集合
     * @param fileName 文件名
     * @param out out
     */
    public static void writer(List<?> dataList, String fileName, OutputStream out) {
        try {
            Workbook workbook;
            String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
            if ("xls".equalsIgnoreCase(suffix)) {
                workbook = new HSSFWorkbook();
            } else if ("xlsx".equalsIgnoreCase(suffix)) {
                workbook = new XSSFWorkbook();
            } else {
                throw new RuntimeException("excel 文件名后缀不合法");
            }

            export(workbook, dataList, out);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static void export(Workbook workbook, List<?> dataList, OutputStream out) throws Exception {

        Sheet sheet = workbook.createSheet();
        Field[] fields = dataList.get(0).getClass().getDeclaredFields();

        // 标题
        Row row = sheet.createRow(0);
        for (Field field : fields) {
            ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
            if (excelProperty != null) {
                row.createCell(excelProperty.index()).setCellValue(excelProperty.name());
            }
        }

        // 数据
        int rowNum = 1;
        for (Object data : dataList) {
            row = sheet.createRow(rowNum++);
            for (Field field : fields) {
                ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
                if (excelProperty == null) {
                    continue;
                }

                Cell cell = row.createCell(excelProperty.index());
                field.setAccessible(true);
                Object fieldValue = field.get(data);

                if (fieldValue == null) {
                    continue;
                }

                if (excelProperty.decode().length > 0) {
                    Map<String, String> map = convertToMap(excelProperty.decode());
                    String cellValue = map.get(fieldValue.toString()) == null ?
                            fieldValue.toString() : map.get(fieldValue.toString());
                    cell.setCellValue(cellValue);
                } else if (fieldValue instanceof Number) {
                    cell.setCellValue(((Number) fieldValue).doubleValue());
                } else if (fieldValue instanceof Date || fieldValue instanceof LocalDate || fieldValue instanceof LocalDateTime) {
                    cell.setCellValue(format(fieldValue, excelProperty.format()));
                } else if (fieldValue instanceof Boolean) {
                    cell.setCellValue((boolean)fieldValue ? excelProperty.bool()[0] : excelProperty.bool()[1]);
                } else {
                    cell.setCellValue(fieldValue.toString());
                }
            }
        }
        workbook.write(out);
        out.close();
    }

    private static Map<String, String> convertToMap(String[] args) {
        Map<String, String> map = new HashMap<>();
        for (int i = 0; i < args.length - 1; i+=2) {
            map.put(args[i + 1], args[i]);
        }
        return map;
    }

    public static String format(Object obj, String pattern) {
        if (obj instanceof Date) {
            return new SimpleDateFormat(pattern).format(obj);
        }
        if (obj instanceof LocalDate) {
            return ((LocalDate) obj).format(DateTimeFormatter.ofPattern(pattern));
        }
        if (obj instanceof LocalDateTime) {
            return ((LocalDateTime) obj).format(DateTimeFormatter.ofPattern(pattern));
        }
        return null;
    }
}
